home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / initsnb.zoo / init / sh / jobs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-09  |  22.2 KB  |  1,038 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)jobs.c    5.1 (Berkeley) 3/7/91";
  39. #endif /* not lint */
  40.  
  41. #include "shell.h"
  42. #if JOBS
  43. #include "sgtty.h"
  44. #undef CEOF            /* syntax.h redefines this */
  45. #endif
  46. #include "main.h"
  47. #include "parser.h"
  48. #include "nodes.h"
  49. #include "jobs.h"
  50. #include "options.h"
  51. #include "trap.h"
  52. #include "signames.h"
  53. #include "syntax.h"
  54. #include "input.h"
  55. #include "output.h"
  56. #include "memalloc.h"
  57. #include "error.h"
  58. #include "mystring.h"
  59. #include <fcntl.h>
  60. #include <signal.h>
  61. #include <errno.h>
  62. #ifdef BSD
  63. #include <sys/types.h>
  64. #include <sys/wait.h>
  65. #include <sys/time.h>
  66. #include <sys/resource.h>
  67. #endif
  68.  
  69.  
  70.  
  71. struct job *jobtab;        /* array of jobs */
  72. int njobs;            /* size of array */
  73. MKINIT short backgndpid = -1;    /* pid of last background process */
  74. #if JOBS
  75. int initialpgrp;        /* pgrp of shell on invocation */
  76. short curjob;            /* current job */
  77. #endif
  78.  
  79. #ifdef __STDC__
  80. STATIC void restartjob(struct job *);
  81. STATIC struct job *getjob(char *);
  82. STATIC void freejob(struct job *);
  83. STATIC int procrunning(int);
  84. STATIC int dowait(int, struct job *);
  85. STATIC int waitproc(int, int *);
  86. STATIC char *commandtext(union node *);
  87. #else
  88. STATIC void restartjob();
  89. STATIC struct job *getjob();
  90. STATIC void freejob();
  91. STATIC int procrunning();
  92. STATIC int dowait();
  93. STATIC int waitproc();
  94. STATIC char *commandtext();
  95. #endif
  96.  
  97.  
  98.  
  99. #if JOBS
  100. /*
  101.  * Turn job control on and off.
  102.  *
  103.  * Note:  This code assumes that the third arg to ioctl is a character
  104.  * pointer, which is true on Berkeley systems but not System V.  Since
  105.  * System V doesn't have job control yet, this isn't a problem now.
  106.  */
  107.  
  108. MKINIT int jobctl;
  109.  
  110. void
  111. setjobctl(on) {
  112.     int ldisc;
  113.  
  114.     if (on == jobctl || rootshell == 0)
  115.         return;
  116.     if (on) {
  117.         do { /* while we are in the background */
  118.             if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
  119.                 out2str("ash: can't access tty; job control turned off\n");
  120.                 jflag = 0;
  121.                 return;
  122.             }
  123.             if (initialpgrp == -1)
  124.                 initialpgrp = getpgrp(0);
  125.             else if (initialpgrp != getpgrp(0)) {
  126.                 killpg(initialpgrp, SIGTTIN);
  127.                 continue;
  128.             }
  129.         } while (0);
  130.         if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
  131.             out2str("ash: need new tty driver to run job control; job control turned off\n");
  132.             jflag = 0;
  133.             return;
  134.         }
  135.         setsignal(SIGTSTP);
  136.         setsignal(SIGTTOU);
  137.         setpgrp(0, rootpid);
  138.         ioctl(2, TIOCSPGRP, (char *)&rootpid);
  139.     } else { /* turning job control off */
  140.         setpgrp(0, initialpgrp);
  141.         ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
  142.         setsignal(SIGTSTP);
  143.         setsignal(SIGTTOU);
  144.     }
  145.     jobctl = on;
  146. }
  147. #endif
  148.  
  149.  
  150. #ifdef mkinit
  151.  
  152. SHELLPROC {
  153.     backgndpid = -1;
  154. #if JOBS
  155.     jobctl = 0;
  156. #endif
  157. }
  158.  
  159. #endif
  160.  
  161.  
  162.  
  163. #if JOBS
  164. fgcmd(argc, argv)  char **argv; {
  165.     struct job *jp;
  166.     int pgrp;
  167.     int status;
  168.  
  169.     jp = getjob(argv[1]);
  170.     if (jp->jobctl == 0)
  171.         error("job not created under job control");
  172.     pgrp = jp->ps[0].pid;
  173.     ioctl(2, TIOCSPGRP, (char *)&pgrp);
  174.     restartjob(jp);
  175.     INTOFF;
  176.     status = waitforjob(jp);
  177.     INTON;
  178.     return status;
  179. }
  180.  
  181.  
  182. bgcmd(argc, argv)  char **argv; {
  183.     struct job *jp;
  184.  
  185.     do {
  186.         jp = getjob(*++argv);
  187.         if (jp->jobctl == 0)
  188.             error("job not created under job control");
  189.         restartjob(jp);
  190.     } while (--argc > 1);
  191.     return 0;
  192. }
  193.  
  194.  
  195. STATIC void
  196. restartjob(jp)
  197.     struct job *jp;
  198.     {
  199.     struct procstat *ps;
  200.     int i;
  201.  
  202.     if (jp->state == JOBDONE)
  203.         return;
  204.     INTOFF;
  205.     killpg(jp->ps[0].pid, SIGCONT);
  206.     for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
  207.         if ((ps->status & 0377) == 0177) {
  208.             ps->status = -1;
  209.             jp->state = 0;
  210.         }
  211.     }
  212.     INTON;
  213. }
  214. #endif
  215.  
  216.  
  217. int
  218. jobscmd(argc, argv)  char **argv; {
  219.     showjobs(0);
  220.     return 0;
  221. }
  222.  
  223.  
  224. /*
  225.  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
  226.  * statuses have changed since the last call to showjobs.
  227.  *
  228.  * If the shell is interrupted in the process of creating a job, the
  229.  * result may be a job structure containing zero processes.  Such structures
  230.  * will be freed here.
  231.  */
  232.  
  233. void
  234. showjobs(change) {
  235.     int jobno;
  236.     int procno;
  237.     int i;
  238.     struct job *jp;
  239.     struct procstat *ps;
  240.     int col;
  241.     char s[64];
  242.  
  243.     TRACE(("showjobs(%d) called\n", change));
  244.     while (dowait(0, (struct job *)NULL) > 0);
  245.     for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
  246.         if (! jp->used)
  247.             continue;
  248.         if (jp->nprocs == 0) {
  249.             freejob(jp);
  250.             continue;
  251.         }
  252.         if (change && ! jp->changed)
  253.             continue;
  254.         procno = jp->nprocs;
  255.         for (ps = jp->ps ; ; ps++) {    /* for each process */
  256.             if (ps == jp->ps)
  257.                 fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
  258.             else
  259.                 fmtstr(s, 64, "    %d ", ps->pid);
  260.             out1str(s);
  261.             col = strlen(s);
  262.             s[0] = '\0';
  263.             if (ps->status == -1) {
  264.                 /* don't print anything */
  265.             } else if ((ps->status & 0xFF) == 0) {
  266.                 fmtstr(s, 64, "Exit %d", ps->status >> 8);
  267.             } else {
  268.                 i = ps->status;
  269. #if JOBS
  270.                 if ((i & 0xFF) == 0177)
  271.                     i >>= 8;
  272. #endif
  273.                 if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F])
  274.                     scopy(sigmesg[i & 0x7F], s);
  275.                 else
  276.                     fmtstr(s, 64, "Signal %d", i & 0x7F);
  277.                 if (i & 0x80)
  278.                     strcat(s, " (core dumped)");
  279.             }
  280.             out1str(s);
  281.             col += strlen(s);
  282.             do {
  283.                 out1c(' ');
  284.                 col++;
  285.             } while (col < 30);
  286.             out1str(ps->cmd);
  287.             out1c('\n');
  288.             if (--procno <= 0)
  289.                 break;
  290.         }
  291.         jp->changed = 0;
  292.         if (jp->state == JOBDONE) {
  293.             freejob(jp);
  294.         }
  295.     }
  296. }
  297.  
  298.  
  299. /*
  300.  * Mark a job structure as unused.
  301.  */
  302.  
  303. STATIC void
  304. freejob(jp)
  305.     struct job *jp;
  306.     {
  307.     struct procstat *ps;
  308.     int i;
  309.  
  310.     INTOFF;
  311.     for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
  312.         if (ps->cmd != nullstr)
  313.             ckfree(ps->cmd);
  314.     }
  315.     if (jp->ps != &jp->ps0)
  316.         ckfree(jp->ps);
  317.     jp->used = 0;
  318. #if JOBS
  319.     if (curjob == jp - jobtab + 1)
  320.         curjob = 0;
  321. #endif
  322.     INTON;
  323. }
  324.  
  325.  
  326.  
  327. int
  328. waitcmd(argc, argv)  char **argv; {
  329.     struct job *job;
  330.     int status;
  331.     struct job *jp;
  332.  
  333.     if (argc > 1) {
  334.         job = getjob(argv[1]);
  335.     } else {
  336.         job = NULL;
  337.     }
  338.     for (;;) {    /* loop until process terminated or stopped */
  339.         if (job != NULL) {
  340.             if (job->state) {
  341.                 status = job->ps[job->nprocs - 1].status;
  342.                 if ((status & 0xFF) == 0)
  343.                     status = status >> 8 & 0xFF;
  344. #if JOBS
  345.                 else if ((status & 0xFF) == 0177)
  346.                     status = (status >> 8 & 0x7F) + 128;
  347. #endif
  348.                 else
  349.                     status = (status & 0x7F) + 128;
  350.                 if (! iflag)
  351.                     freejob(job);
  352.                 return status;
  353.             }
  354.         } else {
  355.             for (jp = jobtab ; ; jp++) {
  356.                 if (jp >= jobtab + njobs) {    /* no running procs */
  357.                     return 0;
  358.                 }
  359.                 if (jp->used && jp->state == 0)
  360.                     break;
  361.             }
  362.         }
  363.         dowait(1, (struct job *)NULL);
  364.     }
  365. }
  366.  
  367.  
  368.  
  369. jobidcmd(argc, argv)  char **argv; {
  370.     struct job *jp;
  371.     int i;
  372.  
  373.     jp = getjob(argv[1]);
  374.     for (i = 0 ; i < jp->nprocs ; ) {
  375.         out1fmt("%d", jp->ps[i].pid);
  376.         out1c(++i < jp->nprocs? ' ' : '\n');
  377.     }
  378.     return 0;
  379. }
  380.  
  381.  
  382.  
  383. /*
  384.  * Convert a job name to a job structure.
  385.  */
  386.  
  387. STATIC struct job *
  388. getjob(name)
  389.     char *name;
  390.     {
  391.     int jobno;
  392.     register struct job *jp;
  393.     int pid;
  394.     int i;
  395.  
  396.     if (name == NULL) {
  397. #if JOBS
  398. currentjob:
  399.         if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
  400.             error("No current job");
  401.         return &jobtab[jobno - 1];
  402. #else
  403.         error("No current job");
  404. #endif
  405.     } else if (name[0] == '%') {
  406.         if (is_digit(name[1])) {
  407.             jobno = number(name + 1);
  408.             if (jobno > 0 && jobno <= njobs
  409.              && jobtab[jobno - 1].used != 0)
  410.                 return &jobtab[jobno - 1];
  411. #if JOBS
  412.         } else if (name[1] == '%' && name[2] == '\0') {
  413.             goto currentjob;
  414. #endif
  415.         } else {
  416.             register struct job *found = NULL;
  417.             for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
  418.                 if (jp->used && jp->nprocs > 0
  419.                  && prefix(name + 1, jp->ps[0].cmd)) {
  420.                     if (found)
  421.                         error("%s: ambiguous", name);
  422.                     found = jp;
  423.                 }
  424.             }
  425.             if (found)
  426.                 return found;
  427.         }
  428.     } else if (is_number(name)) {
  429.         pid = number(name);
  430.         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
  431.             if (jp->used && jp->nprocs > 0
  432.              && jp->ps[jp->nprocs - 1].pid == pid)
  433.                 return jp;
  434.         }
  435.     }
  436.     error("No such job: %s", name);
  437. }
  438.  
  439.  
  440.  
  441. /*
  442.  * Return a new job structure,
  443.  */
  444.  
  445. struct job *
  446. makejob(node, nprocs)
  447.     union node *node;
  448.     {
  449.     int i;
  450.     struct job *jp;
  451.  
  452.     for (i = njobs, jp = jobtab ; ; jp++) {
  453.         if (--i < 0) {
  454.             INTOFF;
  455.             if (njobs == 0) {
  456.                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
  457.             } else {
  458.                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
  459.                 bcopy(jobtab, jp, njobs * sizeof jp[0]);
  460.                 ckfree(jobtab);
  461.                 jobtab = jp;
  462.             }
  463.             jp = jobtab + njobs;
  464.             for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
  465.             INTON;
  466.             break;
  467.         }
  468.         if (jp->used == 0)
  469.             break;
  470.     }
  471.     INTOFF;
  472.     jp->state = 0;
  473.     jp->used = 1;
  474.     jp->changed = 0;
  475.     jp->nprocs = 0;
  476. #if JOBS
  477.     jp->jobctl = jobctl;
  478. #endif
  479.     if (nprocs > 1) {
  480.         jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
  481.     } else {
  482.         jp->ps = &jp->ps0;
  483.     }
  484.     INTON;
  485.     TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1));
  486.     return jp;
  487. }    
  488.  
  489.  
  490. /*
  491.  * Fork of a subshell.  If we are doing job control, give the subshell its
  492.  * own process group.  Jp is a job structure that the job is to be added to.
  493.  * N is the command that will be evaluated by the child.  Both jp and n may
  494.  * be NULL.  The mode parameter can be one of the following:
  495.  *    FORK_FG - Fork off a foreground process.
  496.  *    FORK_BG - Fork off a background process.
  497.  *    FORK_NOJOB - Like FORK_FG, but don't give the process its own
  498.  *             process group even if job control is on.
  499.  *
  500.  * When job control is turned off, background processes have their standard
  501.  * input redirected to /dev/null (except for the second and later processes
  502.  * in a pipeline).
  503.  */
  504.  
  505. int
  506. forkshell(jp, n, mode)
  507.     union node *n;
  508.     struct job *jp;
  509.     {
  510.     int pid;
  511.     int pgrp;
  512. #ifdef __MINT__
  513.     int fd;
  514. #endif
  515.  
  516.     TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode));
  517.     INTOFF;
  518.     pid = fork();
  519.     if (pid == -1) {
  520.         TRACE(("Fork failed, errno=%d\n", errno));
  521.         INTON;
  522.         error("Cannot fork");
  523.     }
  524.     if (pid == 0) {
  525.         struct job *p;
  526.         int wasroot;
  527.         int i;
  528.  
  529.         TRACE(("Child shell %d\n", getpid()));
  530.         wasroot = rootshell;
  531.         rootshell = 0;
  532.         for (i = njobs, p = jobtab ; --i >= 0 ; p++)
  533.             if (p->used)
  534.                 freejob(p);
  535.         closescript();
  536.         INTON;
  537.         clear_traps();
  538. #if JOBS
  539.         jobctl = 0;        /* do job control only in root shell */
  540.         if (wasroot && mode != FORK_NOJOB && jflag) {
  541.             if (jp == NULL || jp->nprocs == 0)
  542.                 pgrp = getpid();
  543.             else
  544.                 pgrp = jp->ps[0].pid;
  545.             setpgrp(0, pgrp);
  546.             if (mode == FORK_FG) {
  547.                 /*** this causes superfluous TIOCSPGRPS ***/
  548.                 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
  549.                     error("TIOCSPGRP failed, errno=%d\n", errno);
  550.             }
  551.             setsignal(SIGTSTP);
  552.             setsignal(SIGTTOU);
  553.         } else if (mode == FORK_BG) {
  554.             ignoresig(SIGINT);
  555.             ignoresig(SIGQUIT);
  556.             if (jp == NULL || jp->nprocs == 0) {
  557.                 close(0);
  558. #ifndef __MINT__
  559.                 if (open("/dev/null", O_RDONLY) != 0)
  560.                     error("Can't open /dev/null");
  561. #else
  562.                 if ((fd = open("/dev/null", O_RDONLY)) < 0)
  563.                     error("Can't open /dev/null");
  564.                 else {
  565.                     dup2(fd, 0);
  566.                     close(fd);
  567.                 }
  568. #endif
  569.             }
  570.         }
  571. #else
  572.         if (mode == FORK_BG) {
  573.             ignoresig(SIGINT);
  574.             ignoresig(SIGQUIT);
  575.             if (jp == NULL || jp->nprocs == 0) {
  576.                 close(0);
  577. #ifndef __MINT__
  578.                 if (open("/dev/null", O_RDONLY) != 0)
  579.                     error("Can't open /dev/null");
  580. #else
  581.                 if ((fd = open("/dev/null", O_RDONLY)) < 0)
  582.                     error("Can't open /dev/null");
  583.                 else {
  584.                     dup2(fd, 0);
  585.                     close(fd);
  586.                 }
  587. #endif
  588.             }
  589.         }
  590. #endif
  591.         if (wasroot && iflag) {
  592.             setsignal(SIGINT);
  593.             setsignal(SIGQUIT);
  594.             setsignal(SIGTERM);
  595.         }
  596.         return pid;
  597.     }
  598.     if (rootshell && mode != FORK_NOJOB && jflag) {
  599.         if (jp == NULL || jp->nprocs == 0)
  600.             pgrp = pid;
  601.         else
  602.             pgrp = jp->ps[0].pid;
  603.         setpgrp(pid, pgrp);
  604.     }
  605.     if (mode == FORK_BG)
  606.         backgndpid = pid;        /* set $! */
  607.     if (jp) {
  608.         struct procstat *ps = &jp->ps[jp->nprocs++];
  609.         ps->pid = pid;
  610.         ps->status = -1;
  611.         ps->cmd = nullstr;
  612.         if (iflag && rootshell && n)
  613.             ps->cmd = commandtext(n);
  614.     }
  615.     INTON;
  616.     TRACE(("In parent shell:  child = %d\n", pid));
  617.     return pid;
  618. }
  619.  
  620.  
  621.  
  622. /*
  623.  * Wait for job to finish.
  624.  *
  625.  * Under job control we have the problem that while a child process is
  626.  * running interrupts generated by the user are sent to the child but not
  627.  * to the shell.  This means that an infinite loop started by an inter-
  628.  * active user may be hard to kill.  With job control turned off, an
  629.  * interactive user may place an interactive program inside a loop.  If
  630.  * the interactive program catches interrupts, the user doesn't want
  631.  * these interrupts to also abort the loop.  The approach we take here
  632.  * is to have the shell ignore interrupt signals while waiting for a
  633.  * forground process to terminate, and then send itself an interrupt
  634.  * signal if the child process was terminated by an interrupt signal.
  635.  * Unfortunately, some programs want to do a bit of cleanup and then
  636.  * exit on interrupt; unless these processes terminate themselves by
  637.  * sending a signal to themselves (instead of calling exit) they will
  638.  * confuse this approach.
  639.  */
  640.  
  641. int
  642. waitforjob(jp)
  643.     register struct job *jp;
  644.     {
  645. #if JOBS
  646.     int mypgrp = getpgrp(0);
  647. #endif
  648.     int status;
  649.     int st;
  650.  
  651.     INTOFF;
  652.     TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
  653.     while (jp->state == 0) {
  654.         dowait(1, jp);
  655.     }
  656. #if JOBS
  657.     if (jp->jobctl) {
  658.         if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
  659.             error("TIOCSPGRP failed, errno=%d\n", errno);
  660.     }
  661.     if (jp->state == JOBSTOPPED)
  662.         curjob = jp - jobtab + 1;
  663. #endif
  664.     status = jp->ps[jp->nprocs - 1].status;
  665.     /* convert to 8 bits */
  666.     if ((status & 0xFF) == 0)
  667.         st = status >> 8 & 0xFF;
  668. #if JOBS
  669.     else if ((status & 0xFF) == 0177)
  670.         st = (status >> 8 & 0x7F) + 128;
  671. #endif
  672.     else
  673.         st = (status & 0x7F) + 128;
  674.     if (! JOBS || jp->state == JOBDONE)
  675.         freejob(jp);
  676.     CLEAR_PENDING_INT;
  677.     if ((status & 0x7F) == SIGINT)
  678.         kill(getpid(), SIGINT);
  679.     INTON;
  680.     return st;
  681. }
  682.  
  683.  
  684.  
  685. /*
  686.  * Wait for a process to terminate.
  687.  */
  688.  
  689. STATIC int
  690. dowait(block, job)
  691.     struct job *job;
  692.     {
  693.     int pid;
  694.     int status;
  695.     struct procstat *sp;
  696.     struct job *jp;
  697.     struct job *thisjob;
  698.     int done;
  699.     int stopped;
  700.     int core;
  701.  
  702.     TRACE(("dowait(%d) called\n", block));
  703.     do {
  704.         pid = waitproc(block, &status);
  705.         TRACE(("wait returns %d, status=%d\n", pid, status));
  706.     } while (pid == -1 && errno == EINTR);
  707.     if (pid <= 0)
  708.         return pid;
  709.     INTOFF;
  710.     thisjob = NULL;
  711.     for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
  712.         if (jp->used) {
  713.             done = 1;
  714.             stopped = 1;
  715.             for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
  716.                 if (sp->pid == -1)
  717.                     continue;
  718.                 if (sp->pid == pid) {
  719.                     TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
  720.                     sp->status = status;
  721.                     thisjob = jp;
  722.                 }
  723.                 if (sp->status == -1)
  724.                     stopped = 0;
  725.                 else if ((sp->status & 0377) == 0177)
  726.                     done = 0;
  727.             }
  728.             if (stopped) {        /* stopped or done */
  729.                 int state = done? JOBDONE : JOBSTOPPED;
  730.                 if (jp->state != state) {
  731.                     TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
  732.                     jp->state = state;
  733. #if JOBS
  734.                     if (done && curjob == jp - jobtab + 1)
  735.                         curjob = 0;        /* no current job */
  736. #endif
  737.                 }
  738.             }
  739.         }
  740.     }
  741.     INTON;
  742.     if (! rootshell || ! iflag || (job && thisjob == job)) {
  743. #if JOBS
  744.         if ((status & 0xFF) == 0177)
  745.             status >>= 8;
  746. #endif
  747.         core = status & 0x80;
  748.         status &= 0x7F;
  749.         if (status != 0 && status != SIGINT && status != SIGPIPE) {
  750.             if (thisjob != job)
  751.                 outfmt(out2, "%d: ", pid);
  752. #if JOBS
  753.             if (status == SIGTSTP && rootshell && iflag)
  754.                 outfmt(out2, "%%%d ", job - jobtab + 1);
  755. #endif
  756.             if (status <= MAXSIG && sigmesg[status])
  757.                 out2str(sigmesg[status]);
  758.             else
  759.                 outfmt(out2, "Signal %d", status);
  760.             if (core)
  761.                 out2str(" - core dumped");
  762.             out2c('\n');
  763.             flushout(&errout);
  764.         } else {
  765.             TRACE(("Not printing status: status=%d\n", status));
  766.         }
  767.     } else {
  768.         TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
  769.         if (thisjob)
  770.             thisjob->changed = 1;
  771.     }
  772.     return pid;
  773. }
  774.  
  775.  
  776.  
  777. /*
  778.  * Do a wait system call.  If job control is compiled in, we accept
  779.  * stopped processes.  If block is zero, we return a value of zero
  780.  * rather than blocking.
  781.  *
  782.  * System V doesn't have a non-blocking wait system call.  It does
  783.  * have a SIGCLD signal that is sent to a process when one of it's
  784.  * children dies.  The obvious way to use SIGCLD would be to install
  785.  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
  786.  * was received, and have waitproc bump another counter when it got
  787.  * the status of a process.  Waitproc would then know that a wait
  788.  * system call would not block if the two counters were different.
  789.  * This approach doesn't work because if a process has children that
  790.  * have not been waited for, System V will send it a SIGCLD when it
  791.  * installs a signal handler for SIGCLD.  What this means is that when
  792.  * a child exits, the shell will be sent SIGCLD signals continuously
  793.  * until is runs out of stack space, unless it does a wait call before
  794.  * restoring the signal handler.  The code below takes advantage of
  795.  * this (mis)feature by installing a signal handler for SIGCLD and
  796.  * then checking to see whether it was called.  If there are any
  797.  * children to be waited for, it will be.
  798.  *
  799.  * If neither SYSV nor BSD is defined, we don't implement nonblocking
  800.  * waits at all.  In this case, the user will not be informed when
  801.  * a background process until the next time she runs a real program
  802.  * (as opposed to running a builtin command or just typing return),
  803.  * and the jobs command may give out of date information.
  804.  */
  805.  
  806. #ifdef SYSV
  807. STATIC int gotsigchild;
  808.  
  809. STATIC int onsigchild() {
  810.     gotsigchild = 1;
  811. }
  812. #endif
  813.  
  814.  
  815. STATIC int
  816. waitproc(block, status)
  817.     int *status;
  818.     {
  819. #ifdef BSD
  820.     int flags;
  821.  
  822. #if JOBS
  823.     flags = WUNTRACED;
  824. #else
  825.     flags = 0;
  826. #endif
  827.     if (block == 0)
  828.         flags |= WNOHANG;
  829.     return wait3((union wait *)status, flags, (struct rusage *)NULL);
  830. #else
  831. #ifdef SYSV
  832.     int (*save)();
  833.  
  834.     if (block == 0) {
  835.         gotsigchild = 0;
  836.         save = signal(SIGCLD, onsigchild);
  837.         signal(SIGCLD, save);
  838.         if (gotsigchild == 0)
  839.             return 0;
  840.     }
  841.     return wait(status);
  842. #else
  843.     if (block == 0)
  844.         return 0;
  845.     return wait(status);
  846. #endif
  847. #endif
  848. }
  849.  
  850.  
  851.  
  852. /*
  853.  * Return a string identifying a command (to be printed by the
  854.  * jobs command.
  855.  */
  856.  
  857. STATIC char *cmdnextc;
  858. STATIC int cmdnleft;
  859. STATIC void cmdtxt(), cmdputs();
  860.  
  861. STATIC char *
  862. commandtext(n)
  863.     union node *n;
  864.     {
  865.     char *name;
  866.  
  867.     cmdnextc = name = ckmalloc(50);
  868.     cmdnleft = 50 - 4;
  869.     cmdtxt(n);
  870.     *cmdnextc = '\0';
  871.     return name;
  872. }
  873.  
  874.  
  875. STATIC void
  876. cmdtxt(n)
  877.     union node *n;
  878.     {
  879.     union node *np;
  880.     struct nodelist *lp;
  881.     char *p;
  882.     int i;
  883.     char s[2];
  884.  
  885.     switch (n->type) {
  886.     case NSEMI:
  887.         cmdtxt(n->nbinary.ch1);
  888.         cmdputs("; ");
  889.         cmdtxt(n->nbinary.ch2);
  890.         break;
  891.     case NAND:
  892.         cmdtxt(n->nbinary.ch1);
  893.         cmdputs(" && ");
  894.         cmdtxt(n->nbinary.ch2);
  895.         break;
  896.     case NOR:
  897.         cmdtxt(n->nbinary.ch1);
  898.         cmdputs(" || ");
  899.         cmdtxt(n->nbinary.ch2);
  900.         break;
  901.     case NPIPE:
  902.         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
  903.             cmdtxt(lp->n);
  904.             if (lp->next)
  905.                 cmdputs(" | ");
  906.         }
  907.         break;
  908.     case NSUBSHELL:
  909.         cmdputs("(");
  910.         cmdtxt(n->nredir.n);
  911.         cmdputs(")");
  912.         break;
  913.     case NREDIR:
  914.     case NBACKGND:
  915.         cmdtxt(n->nredir.n);
  916.         break;
  917.     case NIF:
  918.         cmdputs("if ");
  919.         cmdtxt(n->nif.test);
  920.         cmdputs("; then ");
  921.         cmdtxt(n->nif.ifpart);
  922.         cmdputs("...");
  923.         break;
  924.     case NWHILE:
  925.         cmdputs("while ");
  926.         goto until;
  927.     case NUNTIL:
  928.         cmdputs("until ");
  929. until:
  930.         cmdtxt(n->nbinary.ch1);
  931.         cmdputs("; do ");
  932.         cmdtxt(n->nbinary.ch2);
  933.         cmdputs("; done");
  934.         break;
  935.     case NFOR:
  936.         cmdputs("for ");
  937.         cmdputs(n->nfor.var);
  938.         cmdputs(" in ...");
  939.         break;
  940.     case NCASE:
  941.         cmdputs("case ");
  942.         cmdputs(n->ncase.expr->narg.text);
  943.         cmdputs(" in ...");
  944.         break;
  945.     case NDEFUN:
  946.         cmdputs(n->narg.text);
  947.         cmdputs("() ...");
  948.         break;
  949.     case NCMD:
  950.         for (np = n->ncmd.args ; np ; np = np->narg.next) {
  951.             cmdtxt(np);
  952.             if (np->narg.next)
  953.                 cmdputs(" ");
  954.         }
  955.         for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
  956.             cmdputs(" ");
  957.             cmdtxt(np);
  958.         }
  959.         break;
  960.     case NARG:
  961.         cmdputs(n->narg.text);
  962.         break;
  963.     case NTO:
  964.         p = ">";  i = 1;  goto redir;
  965.     case NAPPEND:
  966.         p = ">>";  i = 1;  goto redir;
  967.     case NTOFD:
  968.         p = ">&";  i = 1;  goto redir;
  969.     case NFROM:
  970.         p = "<";  i = 0;  goto redir;
  971.     case NFROMFD:
  972.         p = "<&";  i = 0;  goto redir;
  973. redir:
  974.         if (n->nfile.fd != i) {
  975.             s[0] = n->nfile.fd + '0';
  976.             s[1] = '\0';
  977.             cmdputs(s);
  978.         }
  979.         cmdputs(p);
  980.         if (n->type == NTOFD || n->type == NFROMFD) {
  981.             s[0] = n->ndup.dupfd + '0';
  982.             s[1] = '\0';
  983.             cmdputs(s);
  984.         } else {
  985.             cmdtxt(n->nfile.fname);
  986.         }
  987.         break;
  988.     case NHERE:
  989.     case NXHERE:
  990.         cmdputs("<<...");
  991.         break;
  992.     default:
  993.         cmdputs("???");
  994.         break;
  995.     }
  996. }
  997.  
  998.  
  999.  
  1000. STATIC void
  1001. cmdputs(s)
  1002.     char *s;
  1003.     {
  1004.     register char *p, *q;
  1005.     register char c;
  1006.     int subtype = 0;
  1007.  
  1008.     if (cmdnleft <= 0)
  1009.         return;
  1010.     p = s;
  1011.     q = cmdnextc;
  1012.     while ((c = *p++) != '\0') {
  1013.         if (c == CTLESC)
  1014.             *q++ = *p++;
  1015.         else if (c == CTLVAR) {
  1016.             *q++ = '$';
  1017.             if (--cmdnleft > 0)
  1018.                 *q++ = '{';
  1019.             subtype = *p++;
  1020.         } else if (c == '=' && subtype != 0) {
  1021.             *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
  1022.             subtype = 0;
  1023.         } else if (c == CTLENDVAR) {
  1024.             *q++ = '}';
  1025.         } else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE)
  1026.             cmdnleft++;        /* ignore it */
  1027.         else
  1028.             *q++ = c;
  1029.         if (--cmdnleft <= 0) {
  1030.             *q++ = '.';
  1031.             *q++ = '.';
  1032.             *q++ = '.';
  1033.             break;
  1034.         }
  1035.     }
  1036.     cmdnextc = q;
  1037. }
  1038.